-- @作者: baidwwy
-- @邮箱:  313738139@qq.com
-- @创建时间:   2015-05-06 16:35:49
-- @最后修改来自: baidwwy
-- @Last Modified time: 2018-08-21 07:14:43
local ffi = require("ffi")
local FFI = {}
setmetatable(ffi, {__index=FFI})
ffi.cdef[[
    //修改窗口图标
    void*   LoadImageA(int,const char*,int,int,int,int);
    int     SendMessageA(int,int,int,void*);
    int     PostMessageA(int,int,int,int);
    //取硬盘序列号
    void*   CreateFileA(const char*,int,int,void*,int,int,void*);
    bool    DeviceIoControl(void*,int,void*,int,void*,int,void*,void*);
    bool    CloseHandle(void*);
    //取窗口信息
    int     GetWindowRect(int,void*);
    //取剪贴板
    int     OpenClipboard(unsigned);
    void*   GetClipboardData(unsigned);
    bool    CloseClipboard();
    void*   GlobalLock(void*);
    int     GlobalUnlock(void*);
    size_t  GlobalSize(void*);
    //置剪贴板
    bool    EmptyClipboard();
    void*   GlobalAlloc(unsigned, unsigned);
    void*   GlobalFree(void*);
    //void*   lstrcpy(void*,const char*);
    void*   SetClipboardData(unsigned,void*);
    //读配置
    int     GetPrivateProfileStringA(const char*, const char*, const char*, const char*, unsigned, const char*);
    //写配置
    bool    WritePrivateProfileStringA(const char*, const char*, const char*, const char*);
    //设置窗口样式
    void    SetWindowLongA(int ,int ,int );
    //取MD5
    typedef struct {
        unsigned long i[2]; /* number of _bits_ handled mod 2^64 */
        unsigned long buf[4]; /* scratch buffer */
        unsigned char in[64]; /* input buffer */
        unsigned char digest[16]; /* actual digest after MD5Final call */
    } MD5_CTX;
    void   __stdcall MD5Init(MD5_CTX *);
    void   __stdcall MD5Update(MD5_CTX *, const char *, unsigned int);
    void   __stdcall MD5Final(MD5_CTX *);
    //信息框
    int     MessageBoxA(void *, const char*, const char*, int);
    //延迟
    void    Sleep(int);
    //文件是否存在
    int     _access(const char*, int);
    //打开网站
    void*   ShellExecuteA(void*, const char *, const char*, const char*, const char*, int);
    //复制文件
    bool    CopyFileA(const char*,const char*,bool );
    //读注册表
    long   __stdcall RegOpenKeyExA(unsigned,const char*,unsigned,unsigned,unsigned*);
    long   __stdcall RegQueryValueExA(unsigned,const char*,unsigned*,unsigned*,char*,unsigned*);
    long   __stdcall RegCloseKey(unsigned);
    //闪烁窗口
    int     FlashWindow(int,bool);
    //查找文件
    typedef struct {
        unsigned    attrib;
        long  time_create;    /* -1 for FAT file systems */
        long  time_access;    /* -1 for FAT file systems */
        long  time_write;
        unsigned long    size;
        char  name[260];
    } _finddata32_t;
    int     _findfirst32(const char*,_finddata32_t*);
    int     _findnext32(int,_finddata32_t*);
    int     _findclose(int);
    //域名转地址
    typedef struct   {
            char   * h_name;           /* official name of host */
            char   ** h_aliases;  /* alias list */
            short   h_addrtype;             /* host address type */
            short   h_length;               /* length of address */
            char   ** h_addr_list; /* list of addresses */
    }hostent;
    hostent* __stdcall gethostbyname(const char *name);
    const char * __stdcall inet_ntop(int,void*,char*,int);
    //控制台
    bool AllocConsole() ;
    void * GetStdHandle(int);
    bool WriteConsoleA(void*,const char*,int,void*,void*);
    bool    SetConsoleTitleA(const char*);
]]
local C = ffi.C
--==========================================================================
function FFI.打开控制台(t)
    if C.AllocConsole() then
        C.SetConsoleTitleA(t or "GGELUA")
        local hd = ffi.C.GetStdHandle(-11)
        return function (...)
            local t= ''
            for i,v in ipairs({...}) do
                t=t..tostring(v).."\t"
            end
            t=t.."\n"
            C.WriteConsoleA(hd,t,#t,nil,nil)
        end
    end
end
function FFI.最小化窗口()
    return C.PostMessageA(引擎.取窗口句柄(),0x0112,0xF020,0)==1
end
function FFI.最大化窗口()
    return C.PostMessageA(引擎.取窗口句柄(),0x0112,0xF030,0)==1
end
function FFI.修改窗口图标(文件)
    local img = C.LoadImageA(0,文件,1,32,32,16)--IMAGE_BITMAP,LR_LOADFROMFILE
    C.SendMessageA(引擎.取窗口句柄(),128,0,img)--WM_SETICON
end
function FFI.取硬盘序列号()
    local h = ffi.gc(C.CreateFileA("\\\\.\\PhysicalDrive0",bit.bor(2147483648,1073741824),bit.bor(1,2),nil,3,0,nil),C.CloseHandle)
    if h ~= ffi.cast('void*',-1) then
        local scip = ffi.new('unsigned char[32]')
        scip[10] = 236
        local data = ffi.new('char[528]')
        local size = ffi.new('int[1]')
        if C.DeviceIoControl(h,508040,scip,32,data,528,size,nil) then
            return ffi.string(data+36,20)
        end
    end
    return ''
end
function FFI.闪烁窗口(v)
    C.FlashWindow(引擎.取窗口句柄(),v)
end
function FFI.取窗口信息()
    local data = ffi.new('int[4]')
    C.GetWindowRect(引擎.取窗口句柄(),data)
    rect = {
        Left    = data[0],
        Top = data[1],
        Right   = data[2],
        Bottom = data[3]
    }
    return rect
end

function FFI.取剪贴板()
    local text = ""
    local ok1    = C.OpenClipboard(0)
    local handle = C.GetClipboardData(1)
    if handle ~= nil then
        local size   = C.GlobalSize( handle )
        local mem    = C.GlobalLock( handle )
        text   = ffi.string( mem, size -1)
        local ok     = C.GlobalUnlock( handle )
    end
    local ok3    = C.CloseClipboard()
    return text
end

function FFI.置剪贴板(txt)
    if txt then
        local ok1 = C.OpenClipboard(0)
        local ok2 = C.EmptyClipboard() --清空
        local handle = C.GlobalAlloc(66, #txt+1)
        if handle ~= nil then
            local mem = C.GlobalLock(handle)
            ffi.copy(mem, txt)
            local ok3 = C.GlobalUnlock(handle)
            handle = C.SetClipboardData(1, mem)
        end
        local ok4 = C.CloseClipboard()
    end
end

function FFI.读配置(文件,节点,名称,默认)
    local buf = ffi.new("char[1024]")
    C.GetPrivateProfileStringA(节点,名称,默认 or "",buf,1024,文件)
    return ffi.string(buf)
end
function FFI.写配置(文件,节点,名称,值)
    return C.WritePrivateProfileStringA(节点,名称,tostring(值),文件)
end

--隐藏边框
--FFI.置窗口样式(引擎.取窗口句柄(),-16,369098752)
function FFI.置窗口样式(h,a,b)
    C.SetWindowLongA(h,a,b)
end
function FFI.取MD5(txt)
    local advapi32 = ffi.load'advapi32'
    local pctx = ffi.new("MD5_CTX[1]")
    advapi32.MD5Init(pctx)
    advapi32.MD5Update(pctx, tostring(txt), string.len(txt))
    advapi32.MD5Final(pctx)

    local md5str = ffi.string(pctx[0].digest,16)
    return string.format("%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",string.byte(md5str, 1, -1))
end
function FFI.信息框(msg,title,type)
    return C.MessageBoxA(nil, msg, title or '信息', type or 0)
end
function FFI.延迟(int)
    C.Sleep(int)
end
function FFI.文件是否存在(file)
    return C._access(file,0)==0
end
-- function FFI.打开网站(file)
--  shell.ShellExecuteA(nil,"open",file,nil,nil,5)
-- end
function FFI.复制文件(原文件,目标文件,覆盖)
    return  C.CopyFileA(原文件,目标文件,覆盖==nil and true or false)
end
--HKEY_CURRENT_USER     0x80000001
--HKEY_LOCAL_MACHINE    0x80000002
--HKEY_USERS            0x80000003
--KEY_READ              0x20019

--REG_SZ                1
--REG_DWORD             4
function FFI.读注册表(根,路径,名称)
    local advapi32 = ffi.load'advapi32'
    local hKey = ffi.new('unsigned [1]')
    if advapi32.RegOpenKeyExA(根,路径,0,0x20019,hKey) == 0 then
        local buf = ffi.new('char[128]')
        -- local REG_SZ = ffi.new('unsigned [1]')
        -- REG_SZ[0] = 1
        local buflen = ffi.new('unsigned [1]')
        buflen[0] = 128
        if advapi32.RegQueryValueExA(hKey[0],名称,nil,nil,buf,buflen) == 0 then
            return ffi.string(buf)
        end
        advapi32.RegCloseKey(hKey[0])
    end
    return ''
end
function FFI.查找文件(目录,筛选,子目录,表)
    local result = 表 or {}
    local file = ffi.new("_finddata32_t")
    local HANDLE = C._findfirst32(目录..'/*.*',file)
    if HANDLE ~= -1 then
        repeat
            local name = ffi.string(file.name)
            if name ~= '.' and name ~='..' then
                if bit.band(file.attrib,16) == 16 then
                    if 子目录 then
                        FFI.查找文件(目录..'/'..name,筛选,子目录,result)
                    end
                elseif name == 筛选 or name:match("%w+$")==筛选 then--全名或者扩展名
                    table.insert(result, 目录.."/"..name)
                end
            end
        until C._findnext32(HANDLE,file)==-1
    end
    C._findclose(HANDLE)
    return result
end

function FFI.域名转地址(域名)
    local ws2_32 = ffi.load'ws2_32'

    local h = ws2_32.gethostbyname(域名)
    if h~=nil then
        local ip = ffi.new('char[32]')
        return ffi.string(ws2_32.inet_ntop(h.h_addrtype,h.h_addr_list[0],ip,32))
    end
end

--[==[
local ffi = require("ffi")
ffi.cdef[[
int __stdcall  CryptBinaryToStringA(
        const char *pbBinary,
        int  cbBinary,
        int  dwFlags,
        char * pszString,
        int *pcchString
);
int __stdcall CryptStringToBinaryA(
        const char *pszString,
        int  cchString,
        int  dwFlags,
    char *pbBinary,
        int  *pcbBinary,
        int  *pdwSkip,
        int  *pdwFlags
);
]]
local crypt = ffi.load(ffi.os == "Windows" and "crypt32")

local function toBase64(txt)
    local buflen = ffi.new("int[1]")
    crypt.CryptBinaryToStringA(txt, #txt, 1, nil, buflen)

    local buf = ffi.new("char[?]", buflen[0])
    crypt.CryptBinaryToStringA(txt, #txt, 1, buf, buflen)
    return ffi.string(buf, buflen[0])
end

local function fromBase64(txt)
    local buflen = ffi.new("int[1]")
    crypt.CryptStringToBinaryA(txt, #txt, 1, nil, buflen, nil, nil)

    local buf = ffi.new("char[?]", buflen[0])
    crypt.CryptStringToBinaryA(txt, #txt, 1, buf, buflen, nil, nil)
    return ffi.string(buf, buflen[0])
end
]==]

return FFI